package wkt.basic;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import net.xnzn.framework.config.exception.BizRuntimeException;
import net.xnzn.framework.id.Id;
import net.xnzn.framework.secure.filter.annotation.RequiresAuthentication;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import wkt.student.Student;
import wkt.student.StudentMapper;

import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/basic")
@RequiresAuthentication
public class BasicController {
    public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    @Autowired
    private BasicMapper basicMapper;
    @Autowired
    private BasicExamDateMapper basicExamDateMapper;
    @Autowired
    private StudentMapper studentMapper;

    @PostMapping("/list-tree")
    public List<Basic> listTree() {
        List<Basic> basics = basicMapper.selectList(Wrappers.lambdaQuery(Basic.class)
                .select(Basic::getId, Basic::getName, Basic::getCode, Basic::getType, Basic::getParentId, Basic::getPath)
                .eq(Basic::getState, "NORMAL")
                .orderByAsc(Basic::getOrders)
                .orderByAsc(Basic::getId));
        final Map<Long, List<Basic>> parentId_children = basics.stream().collect(Collectors.groupingBy(Basic::getParentId));
        basics.forEach(basic -> basic.setChildren(parentId_children.get(basic.getId())));
        return basics.stream().filter(basic -> basic.getParentId() == 0).collect(Collectors.toList());
    }

    @PostMapping("/get")
    public Basic get(@RequestBody Basic basic) {
        return basicMapper.selectOne(Wrappers.lambdaQuery(Basic.class)
                .select(Basic::getId, Basic::getName, Basic::getCode, Basic::getType, Basic::getParentId, Basic::getPath)
                .eq(Basic::getId, basic.getId()));
    }

    @PostMapping("/delete")
    public void delete(@RequestBody Basic basic) {
        final String path = get(new Basic(basic.getId())).getPath();
        basicMapper.update(null, Wrappers.lambdaUpdate(Basic.class)
                .likeRight(Basic::getPath, path)
                .set(Basic::getState, "DELETE"));
    }

    @PostMapping("/upsert")
    public void update(@RequestBody Basic basic) {
        if (basic.getId() == null) {
            basic.setId(Id.next());
            if (basic.getParentId() == 0) {
                basic.setPath("|0|" + basic.getId());
            } else {
                basic.setPath(get(new Basic(basic.getParentId())).getPath() + "|" + basic.getId());
            }
            basicMapper.insert(basic);
            return;
        }
        basicMapper.update(null, Wrappers.lambdaUpdate(Basic.class)
                .eq(Basic::getId, basic.getId())
                .set(Basic::getName, basic.getName())
                .set(Basic::getCode, basic.getCode()));
    }

    @PostMapping("/exam-date/list")
    public List<BasicExamDate> listTree(@RequestBody BasicExamDate basicExamDate) {
        return basicExamDateMapper.selectList(Wrappers.lambdaQuery(BasicExamDate.class)
                .select(BasicExamDate::getId, BasicExamDate::getBasicId, BasicExamDate::getDate)
                .eq(BasicExamDate::getBasicId, basicExamDate.getBasicId())
                .eq(BasicExamDate::getState, "NORMAL")
                .orderByDesc(BasicExamDate::getDate));
    }

    @PostMapping("/exam-date/select-list")
    public List<Basic> listSelectTree() {
        List<Basic> basics = basicMapper.selectList(Wrappers.lambdaQuery(Basic.class)
                .select(Basic::getId, Basic::getName, Basic::getCode, Basic::getType, Basic::getParentId)
                .eq(Basic::getState, "NORMAL")
                .ne(Basic::getType, "KEMU")
                .orderByAsc(Basic::getOrders)
                .orderByAsc(Basic::getId));
        final List<BasicExamDate> basicExamDates = basicExamDateMapper.selectList(Wrappers.lambdaQuery(BasicExamDate.class)
                .select(BasicExamDate::getId, BasicExamDate::getBasicId, BasicExamDate::getDate)
                .eq(BasicExamDate::getState, "NORMAL")
                .orderByDesc(BasicExamDate::getDate));
        final Map<Long, List<Basic>> basicId_examDate = basicExamDates.stream().collect(
                Collectors.groupingBy(
                        BasicExamDate::getBasicId,
                        Collectors.mapping(
                                examDate -> new Basic(examDate.getId(), examDate.getDate().format(DATE_FORMATTER)),
                                Collectors.toList()
                        )
                )
        );

        final Map<Long, List<Basic>> parentId_children = basics.stream().collect(Collectors.groupingBy(Basic::getParentId));
        basics.forEach(basic -> {
            if ("ZHUANYE".equals(basic.getType())) {
                basic.setChildren(basicId_examDate.get(basic.getId()));
                return;
            }
            basic.setChildren(parentId_children.get(basic.getId()));
        });
        return basics.stream().filter(basic -> basic.getParentId() == 0).collect(Collectors.toList());
    }

    @PostMapping("/exam-date/get")
    public BasicExamDate getExamDate(@RequestBody BasicExamDate basicExamDate) {
        return basicExamDateMapper.selectOne(Wrappers.lambdaQuery(BasicExamDate.class)
                .select(BasicExamDate::getId, BasicExamDate::getBasicId, BasicExamDate::getDate)
                .eq(BasicExamDate::getId, basicExamDate.getId()));
    }

    @PostMapping("/exam-date/delete")
    public void deleteExamDate(@RequestBody BasicExamDate basicExamDate) {
        final Student student = studentMapper.selectOne(Wrappers.lambdaQuery(Student.class).select(Student::getId).eq(Student::getState, "NORMAL").eq(Student::getExamDateId, basicExamDate.getId()).last("limit 1"));
        if (student != null) throw new BizRuntimeException("该科目时间已有报名的学生,不能删除");

        basicExamDateMapper.update(null, Wrappers.lambdaUpdate(BasicExamDate.class)
                .eq(BasicExamDate::getId, basicExamDate.getId())
                .set(BasicExamDate::getState, "DELETE"));
    }

    @PostMapping("/exam-date/upsert")
    public void update(@RequestBody BasicExamDate basicExamDate) {
        final LambdaQueryWrapper<BasicExamDate> queryWrapper = Wrappers.lambdaQuery(BasicExamDate.class)
                .select(BasicExamDate::getId, BasicExamDate::getBasicId, BasicExamDate::getDate)
                .eq(BasicExamDate::getBasicId, basicExamDate.getBasicId())
                .eq(BasicExamDate::getState, "NORMAL")
                .eq(BasicExamDate::getDate, basicExamDate.getDate()).last("limit 1");
        if (basicExamDate.getId() != null) queryWrapper.ne(BasicExamDate::getId, basicExamDate.getId());

        final BasicExamDate examDate = basicExamDateMapper.selectOne(queryWrapper);
        if (examDate != null) throw new BizRuntimeException("当前科目已存在指定的考试日期");

        if (basicExamDate.getId() == null) {
            basicExamDate.setId(Id.next());
            basicExamDateMapper.insert(basicExamDate);
            return;
        }
        basicExamDateMapper.update(null, Wrappers.lambdaUpdate(BasicExamDate.class)
                .eq(BasicExamDate::getId, basicExamDate.getId())
                .set(BasicExamDate::getDate, basicExamDate.getDate()));
    }
}
